package com.cys.dm.rest.service;

import com.alibaba.fastjson.JSON;
import com.cys.dm.client.base.DmImageClient;
import com.cys.dm.client.item.DmItemClient;
import com.cys.dm.client.order.DmOrderClient;
import com.cys.dm.client.order.DmOrderLinkUserClient;
import com.cys.dm.client.scheduler.DmSchedulerSeatClient;
import com.cys.dm.client.scheduler.DmSchedulerSeatPriceClient;
import com.cys.dm.client.user.DmLinkUserClient;
import com.cys.dm.client.user.DmUserClient;
import com.cys.dm.entity.base.DmImage;
import com.cys.dm.entity.item.DmItem;
import com.cys.dm.entity.order.DmOrder;
import com.cys.dm.entity.order.DmOrderLinkUser;
import com.cys.dm.entity.scheduler.DmSchedulerSeat;
import com.cys.dm.entity.scheduler.DmSchedulerSeatPrice;
import com.cys.dm.entity.user.DmLinkUser;
import com.cys.dm.entity.user.DmUser;
import com.cys.dm.exceptions.DmException;
import com.cys.dm.utils.IdWorker;
import com.cys.dm.utils.MD5;
import com.cys.dm.utils.UserAgentUtil;
import com.cys.dm.vo.UserTokenResponse;
import com.cys.dm.vo.order.reception.OrderDscReception;
import com.cys.dm.vo.order.reception.OrderReception;
import com.cys.dm.vo.order.response.OrderResponse;
import com.cys.dm.vo.user.QueryPersonInfoVo;
import cz.mallat.uasparser.UASparser;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author blue_t
 * @date 2020-12-27 10:30
 */
@Service
public class DmOrderService {
    @Autowired
    private DmOrderClient dmOrderClient;
    @Autowired
    private DmItemClient dmItemClient;
    @Autowired
    private DmUserClient dmUserClient;
    @Autowired
    private DmImageClient dmImageClient;
    @Autowired
    private DmSchedulerSeatClient dmSchedulerSeatClient;
    @Autowired
    private DmSchedulerSeatPriceClient dmSchedulerSeatPriceClient;
    @Autowired
    private DmLinkUserClient dmLinkUserClient;
    @Autowired
    private DmOrderLinkUserClient dmOrderLinkUserClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    private MessagePostProcessor messagePostProcessor = message -> {
        MessageProperties messageProperties = message.getMessageProperties();
        //设置编码
        messageProperties.setContentEncoding("utf-8");
        //设置过期时间10*1000毫秒
        messageProperties.setExpiration("10000");
        return message;
    };

    public String submitorder(OrderReception orderReception){
        //判断是否被锁
        while (redisTemplate.opsForValue().get("orderLock") != null){
            System.out.println("循环调用锁");
        }

        if (redisTemplate.opsForValue().get("orderLock") == null){
            //加锁
            redisTemplate.opsForValue().set("orderLock","lock");
            System.out.println("加锁");
        }

        //1、判断商品是否存在
        Long itemId = orderReception.getItemId();
        DmItem dmItem = dmItemClient.findByIdForItem(itemId);
        if (dmItem == null){
            redisTemplate.delete("orderLock");
            throw new DmException("商品不存在");
        }

        //座位数组
        String[] seats = orderReception.getSeatPositions().split(",");
        //座位价格数组
        Double[] prices = new Double[seats.length];
        //订单联系人身份证号数组
        String[] orderLikes = orderReception.getLinkIds().split(",");

        //开始添加订单
        DmOrder dmOrder = new DmOrder();
        //下单编号
        dmOrder.setOrderNo(IdWorker.getId());
        //下单用户
        dmOrder.setUserId(orderReception.getUserId());
        //排期Id
        dmOrder.setSchedulerId(orderReception.getSchedulerId());
        //商品Id
        dmOrder.setItemId(dmItem.getId());
        //商品名称
        dmOrder.setItemName(dmItem.getItemName());
        //微信交易号
        dmOrder.setSourceType(0);
        //订单类型 0:未支付 -1:支付超时/支付取消 2:已支付
        dmOrder.setOrderType(0);
        //购买数量 有几个座位数就是有几个购买数量
        dmOrder.setTotalCount(seats.length);

        //发票
        dmOrder.setIsNeedInvoice(orderReception.getIsNeedInvoice());
        //判断是否需要发票
        if (orderReception.getIsNeedInvoice() != 0 && orderReception.getIsNeedInvoice() != null){
            //发票类型
            dmOrder.setInvoiceType(orderReception.getInvoiceType());
            //发票抬头
            dmOrder.setInvoiceHead(orderReception.getInvoiceHead());
            //发票号
            dmOrder.setInvoiceNo(orderReception.getInvoiceNo());
        }

        //计算总价
        Double totalPrice = 0d;
        List<DmSchedulerSeat> schedulerSeats = new ArrayList<>();
        for (int i = 0; i < seats.length; i++) {
            //获取x轴
            Integer x = Integer.parseInt(seats[i].split("_")[0]);
            //获取y轴
            Integer y = Integer.parseInt(seats[i].split("_")[1]);
            //根据排期id座位x，y轴准确获取座位信息
            DmSchedulerSeat schedulerSeat = dmSchedulerSeatClient.findSchedulerSeatByIdAndXAndY(orderReception.getSchedulerId(), x, y);

            //判断座位状态
            if (schedulerSeat.getStatus() != 1){
                redisTemplate.delete("orderLock");
                throw new DmException("2001","已经被购买!");
            }

            //保存座位信息
            //订单编号
            schedulerSeat.setOrderNo(dmOrder.getOrderNo());
            //下单用户
            schedulerSeat.setUserId(orderReception.getUserId());
            //订单状态(锁定订单 待支付)
            schedulerSeat.setStatus(2);
            //保存所有要购买的座位
            schedulerSeats.add(schedulerSeat);


            //获取票价
            DmSchedulerSeatPrice seatPrice = dmSchedulerSeatPriceClient.findSeatPriceByScheduleIdAndLevel(schedulerSeat.getScheduleId(), schedulerSeat.getAreaLevel());

            //储存票价
            prices[i] = seatPrice.getPrice();
            //获取总价
            totalPrice += seatPrice.getPrice();

            //判断是否购买了保险
            if (orderReception.getIsNeedInsurance() == 1){
                totalPrice+= 20d;
            }
        }

        //订单总价
        dmOrder.setTotalAmount(totalPrice);
        dmOrder.setIsNeedInvoice(20);

        /**
         * 添加订单
         * 添加失败事务回滚
         */
        try {
            dmOrderClient.addOrder(dmOrder);
        }catch (Exception e){
            e.printStackTrace();
            //事务回滚
            //1、删除订单
            rabbitTemplate.convertAndSend("dm-order-back",dmOrder.getOrderNo());
            //2、释放锁
            redisTemplate.delete("orderLock");
            throw new DmException("2002","添加订单失败!");
        }

        //3、修改座位状态
        try {
            schedulerSeats.forEach(dmSchedulerSeat -> {
                dmSchedulerSeatClient.updateSeatByXAndYAndScheduleId(dmSchedulerSeat);
                System.out.println("修改座位成功---------");
            });
        }catch (Exception e){
            e.printStackTrace();
            //事务回滚
            //1、删除订单
            rabbitTemplate.convertAndSend("dm-order-back",dmOrder.getOrderNo());
            //2、修改座位状态
            //修改集合中的座位状态
            schedulerSeats.forEach(x->x.setStatus(1));
            rabbitTemplate.convertAndSend("dm-scheduler-seat-back",schedulerSeats);
            //3、释放锁
            redisTemplate.delete("orderLock");
            throw new DmException("2003","抢购座位失败！");
        }

        //4、添加订单联系人
        List<DmOrderLinkUser> dmOrderLinkUserList = new ArrayList<>();
        //添加订单联系人
        try {
            for (int i = 0; i < orderLikes.length; i++) {
                //订单联系人身份证号
                Long idCard = Long.parseLong(orderLikes[i]);
                //常用联系人
                DmLinkUser dmLinkUser = dmLinkUserClient.findLinkUserByIdCard(idCard);
                //开始订单常用添加
                DmOrderLinkUser orderLinkUser = new DmOrderLinkUser();
                //用户ID
                orderLinkUser.setLinkUserId(dmLinkUser.getUserId());
                //用户名称
                orderLinkUser.setLinkUserName(dmLinkUser.getName());
                //订单ID
                orderLinkUser.setOrderId(Long.parseLong(dmOrder.getOrderNo()));
                //X轴
                orderLinkUser.setX(Integer.parseInt(seats[i].split("_")[0]));
                //Y轴
                orderLinkUser.setY(Integer.parseInt(seats[i].split("_")[1]));
                //价格
                orderLinkUser.setPrice(prices[i]);
                dmOrderLinkUserList.add(orderLinkUser);
            }

            dmOrderLinkUserList.forEach(dmOrderLinkUser -> {
                dmOrderLinkUserClient.addOrderLinkUser(dmOrderLinkUser);
            });
        }catch (Exception e){
            e.printStackTrace();
            //事务回滚
            //1、删除订单
            rabbitTemplate.convertAndSend("dm-order-back",dmOrder.getOrderNo());
            //2、修改座位状态
            //修改集合中的座位状态
            schedulerSeats.forEach(x->x.setStatus(1));
            rabbitTemplate.convertAndSend("dm-scheduler-seat-back",schedulerSeats);
            //3、删除订单联系人
            rabbitTemplate.convertAndSend("dm-order-link-user-back",dmOrderLinkUserList);
            //4、释放锁
            redisTemplate.delete("orderLock");
            throw new DmException("2004","添加订单联系人失败！");
        }

        //添加到死信队列


        //释放锁
        System.out.println("释放锁----");
        redisTemplate.delete("orderLock");

        //设置订单十五分钟过期
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());// 生成一个消息
        // 声明消息处理器  设置消息的编码以及消息的过期时间  时间毫秒值 为字符串
        MessagePostProcessor messagePostProcessor = message -> {
            MessageProperties messageProperties = message.getMessageProperties();
            // 设置编码
            messageProperties.setContentEncoding("utf-8");
            // 设置过期时间 15分钟
            int expiration = (1000 * 60) * 15;
            messageProperties.setExpiration(String.valueOf(expiration));
            return message;
        };
        String orderNo = dmOrder.getOrderNo();
        rabbitTemplate.convertAndSend("ORDER_DL_EXCHANGE","DL_KEY",orderNo,messagePostProcessor,correlationData);
        System.out.println(new Date() +  "发送消息，订单号为" + orderNo);

        return dmOrder.getOrderNo();
    }

    public List<OrderResponse> queryorderlist(HttpServletRequest request, OrderDscReception orderDsc){
        //获取当前用户Id
        String[] tokens = request.getHeader("token").split("-");
        long userId = Long.parseLong(tokens[2]);
        //返回查询订单结果
        List<DmOrder> orders = dmOrderClient.findByTypeAndTimeAndKey(orderDsc.getOrderType(),orderDsc.getOrderTime(),orderDsc.getKeyword(),userId);

        List<OrderResponse> orderReceptions = new ArrayList<>();
        orders.forEach(order -> {
            OrderResponse orderVo = new OrderResponse();
            //订单Id
            orderVo.setId(order.getId());
            //订单编号
            orderVo.setOrderNo(order.getOrderNo());
            //商品名称
            orderVo.setItemName(order.getItemName());
            //总价
            orderVo.setTotalAmount(order.getTotalAmount());
            //订单类型
            orderVo.setOrderType(order.getOrderType());
            //购买数量
            orderVo.setNum(order.getTotalCount());
            //商品单价
            //判断是否购买保险
            if (order.getIsNeedInsurance() == 0){
                //没有保险
                orderVo.setUnitPrice(order.getTotalAmount()/order.getTotalCount());
            }else{
                //有保险
                //判断有几个人
                Long totalCount = order.getTotalCount();
                orderVo.setUnitPrice(order.getTotalAmount() - (20*totalCount)/order.getTotalCount());
            }

            //购买时间
            orderVo.setSellTime(order.getCreatedTime());

            orderReceptions.add(orderVo);
        });


        return orderReceptions;
    }

    /**
     * 根据用户Id获取用户信息
     * @param map
     * @return
     */
    public QueryPersonInfoVo querypersoninfo(Map<String,Long> map){
        //根据用户ID查询用户信息
        Long userId = map.get("userId");
        DmUser dmUser = dmUserClient.findById(userId);
        QueryPersonInfoVo queryPersonInfoVo = new QueryPersonInfoVo();
        queryPersonInfoVo.setNickName(dmUser.getNickName());
        queryPersonInfoVo.setPhone(dmUser.getPhone());
        queryPersonInfoVo.setRealName(dmUser.getRealName());
        queryPersonInfoVo.setSex(dmUser.getSex());
        queryPersonInfoVo.setIdCard(dmUser.getIdCard());
        queryPersonInfoVo.setBirthday(dmUser.getBirthday());
        queryPersonInfoVo.setHobby(dmUser.getHobby());
        //根据用户地Id查询头像图片
        DmImage dmImage = dmImageClient.findUserPicByIDAndType(userId,0L);
        queryPersonInfoVo.setImgUrl(dmImage.getImgUrl());
        return queryPersonInfoVo;
    }

    /**
     * 修改用户信息
     * @param request
     * @param response
     * @param queryPersonInfoVo
     * @return
     * @throws IOException
     */
    public UserTokenResponse modifypersoninfo(HttpServletRequest request, HttpServletResponse response,QueryPersonInfoVo queryPersonInfoVo) throws IOException {
        //获取token
        String token = request.getHeader("token");
        String dmUserStr = (String) redisTemplate.opsForValue().get(token);

        //redis里面的用户
        DmUser dmUser = JSON.parseObject(dmUserStr, DmUser.class);
        //要修改的用户
        DmUser newUser = new DmUser();

        BeanUtils.copyProperties(queryPersonInfoVo,newUser);
        newUser.setId(dmUser.getId());

        //修改用户信息
        Integer integer = dmUserClient.updateUserById(newUser);

        //将redis的token信息进行替换

        //删除token
        redisTemplate.delete(token);

        //获取要存储的token的Value信息
        DmUser tokenUser = dmUserClient.findByPhoneAndPassword(dmUser.getPhone(), dmUser.getPassword());
        System.out.println(tokenUser+"------");
        //获取token的key信息
        //自定义token
        StringBuffer stringBuffer = new StringBuffer("token:PC-");
        stringBuffer.append(tokenUser.getPhone()+"-");
        stringBuffer.append(tokenUser.getId()+"-");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        Date genDate = new Date();
        String genTime = dateFormat.format(genDate);
        stringBuffer.append(genTime+"-");
        UASparser uaSparser =  UserAgentUtil.getUasParser();
        String userAgent = request.getHeader("User-Agent");
        stringBuffer.append(MD5.getMd5(uaSparser.parse(userAgent).getDeviceType(),6));
        //redis存储token,两个小时过期
        redisTemplate.opsForValue().set(stringBuffer.toString(), JSON.toJSONString(tokenUser),2, TimeUnit.HOURS);

        UserTokenResponse userTokenResponse = new UserTokenResponse();
        userTokenResponse.setUserId(tokenUser.getId());
        userTokenResponse.setSex(tokenUser.getSex());
        userTokenResponse.setIdCard(tokenUser.getIdCard());
        userTokenResponse.setNickName(tokenUser.getNickName());
        userTokenResponse.setRealName(tokenUser.getRealName());
        userTokenResponse.setPhone(tokenUser.getPhone());
        userTokenResponse.setToken(stringBuffer.toString());
        userTokenResponse.setGenTime(genDate.getTime());
        userTokenResponse.setExtTime(genDate.getTime()+(1000 * 60 * 60 * 2));

        return userTokenResponse;
    }
}
